package org.foreverframework.account.persist;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class AccountPersistServiceImpl implements AccountPersistService {

	private static final String UTF_8 = "UTF-8";
	private static final String ELEMENT_ACCOUNT_ACTIVATED = "activated";
	private static final String ELEMENT_ACCOUNT_PASSWORD = "password";
	private static final String ELEMENT_ACCOUNT_EMAIL = "email";
	private static final String ELEMENT_ACCOUNT_NAME = "name";
	private static final String ELEMENT_ACCOUNT_ID = "id";
	private static final String ELEMENT_ACCOUNT = "account";
	private static final String ELEMENT_ACCOUNTS = "accounts";
	private static final String ELEMENT_ROOT = "account-persist";
	private String filePath;
	private SAXReader reader = new SAXReader();

	public AccountPersistServiceImpl() {
		
	}
	
	public void checkFile() throws AccountPersistException {
		File dataFile = new File(filePath).getAbsoluteFile();
		if (!dataFile.exists()) {
			File parentFile = dataFile.getParentFile();
			parentFile.mkdirs();
			Document doc = DocumentFactory.getInstance().createDocument();
			doc.addElement(ELEMENT_ROOT).addElement(ELEMENT_ACCOUNTS);
			writeDoc(doc);
		}
	}

	public Document readDocument() throws AccountPersistException {
		checkFile();
		try {
			Document doc = reader.read(new File(filePath));
			return doc;
		} catch (DocumentException e) {
			throw new AccountPersistException(
					"Unable to read persist data xml", e);
		}
	}

	public Account createAccount(Account account)
			throws AccountPersistException {
		Element element = buildAccountElement(account);
		Document doc = readDocument();
		doc.getRootElement().element(ELEMENT_ACCOUNTS).add(element);
		writeDoc(doc);
		return account;
	}

	private Element buildAccountElement(Account account) {
		Element element = DocumentFactory.getInstance().createElement(
				ELEMENT_ACCOUNT);
		element.addElement(ELEMENT_ACCOUNT_ID).setText(account.getId());
		element.addElement(ELEMENT_ACCOUNT_NAME).setText(account.getName());
		element.addElement(ELEMENT_ACCOUNT_EMAIL).setText(account.getEmail());
		element.addElement(ELEMENT_ACCOUNT_PASSWORD).setText(
				account.getPassword());
		element.addElement(ELEMENT_ACCOUNT_ACTIVATED).setText(
				String.valueOf(account.isActivated()));
		return element;
	}

	private void writeDoc(Document doc) throws AccountPersistException {
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding(UTF_8);
		XMLWriter writer = null;
		try {
			writer = new XMLWriter(new FileWriter(filePath), format);
			writer.write(doc);
		} catch (IOException e) {
			throw new AccountPersistException(
					"Unable to write persist data xml", e);
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					throw new AccountPersistException(
							"Unable to close persist data xml writer", e);
				}
			}
		}
	}

	public Account readAccount(String id) throws AccountPersistException {
		Document doc = readDocument();
		Element accountsEle = doc.getRootElement().element(ELEMENT_ACCOUNTS);
		for (Object obj : accountsEle.elements()) {
			Element accountEle = (Element) obj;
			if (accountEle.elementTextTrim(ELEMENT_ACCOUNT_ID).equals(id)) {
				return buildAccount(accountEle);
			}
		}
		return null;
	}

	private Account buildAccount(Element accountEle) {
		Account account = new Account();
		account.setId(accountEle.elementTextTrim(ELEMENT_ACCOUNT_ID));
		account.setName(accountEle.elementText(ELEMENT_ACCOUNT_NAME));
		account.setEmail(accountEle.elementTextTrim(ELEMENT_ACCOUNT_EMAIL));
		account.setPassword(accountEle
				.elementTextTrim(ELEMENT_ACCOUNT_PASSWORD));
		account.setActivated(new Boolean(accountEle
				.elementTextTrim(ELEMENT_ACCOUNT_ACTIVATED)));
		return account;
	}

	public Account updateAccount(Account account)
			throws AccountPersistException {
		if (readAccount(account.getId()) != null) {
			deleteAccount(account.getId());
			createAccount(account);
		}
		return account;
	}

	public void deleteAccount(String id) throws AccountPersistException {
		Document doc = readDocument();
		for (Object obj : doc.getRootElement().element(ELEMENT_ACCOUNTS)
				.elements()) {
			Element accountEle = (Element) obj;
			if (accountEle.elementTextTrim(ELEMENT_ACCOUNT_ID).equals(id)) {
				accountEle.detach();
				writeDoc(doc);
				return;
			}
		}
	}

	public String getFile() {
		return filePath;
	}

	public void setFile(String file) {
		this.filePath = file;
	}

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

}
